package com.clouddms.controller;

import com.clouddms.dto.LoginRequest;
import com.clouddms.dto.RegisterRequest;
import com.clouddms.entity.User;
import com.clouddms.entity.Admin;
import com.clouddms.service.auth.UserService;
import com.clouddms.service.auth.TokenBlacklistService;
import com.clouddms.repository.AdminRepository;
import com.clouddms.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpSession;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * 认证控制器
 * 处理用户登录、注销等认证相关请求
 *
 * @author Cloud-DMS Team
 * @version 1.0.0
 */
@Slf4j
@Controller
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private UserService userService;

    @Autowired
    private AdminRepository adminRepository;

    @Autowired
    private JwtUtil jwtUtil;

    @Autowired
    private TokenBlacklistService tokenBlacklistService;

    /**
     * 用户登录页面
     */
    @GetMapping("/user-login")
    public String userLoginPage() {
        return "user-login";
    }

    /**
     * 管理员登录页面
     */
    @GetMapping("/admin-login")
    public String adminLoginPage() {
        return "admin-login";
    }

    /**
     * 默认登录页面重定向到用户登录
     */
    @GetMapping("/login")
    public String loginPage() {
        return "redirect:/auth/user-login";
    }

    /**
     * 用户注册页面
     */
    @GetMapping("/register")
    public String registerPage() {
        return "user-register";
    }

    /**
     * 用户登录处理
     */
    @PostMapping("/user-login")
    @ResponseBody
    public Map<String, Object> userLogin(@RequestBody LoginRequest loginRequest, HttpSession session) {
        Map<String, Object> response = new HashMap<>();
        
        try {
            log.info("用户登录请求: {}", loginRequest.getUsername());
            
            // 验证用户凭据
            if (isValidUser(loginRequest.getUsername(), loginRequest.getPassword())) {
                String userRole = getUserRole(loginRequest.getUsername());
                
                // 检查是否为普通用户
                if (!"USER".equals(userRole)) {
                    response.put("success", false);
                    response.put("message", "登录渠道、账户或密码不正确，请重试");
                    log.warn("非普通用户尝试通过用户渠道登录: {}, 角色: {}", loginRequest.getUsername(), userRole);
                    return response;
                }
                
                // 登录成功，设置session
                Long userId = getUserId(loginRequest.getUsername());
                session.setAttribute("username", loginRequest.getUsername());
                session.setAttribute("userId", userId);
                session.setAttribute("userRole", userRole);
                session.setAttribute("isAuthenticated", true);
                
                // 生成JWT Token供前端使用
                Set<String> roles = new HashSet<>();
                roles.add(userRole);
                
                // 撤销该用户的旧Token
                tokenBlacklistService.revokeUserTokens(userId);
                
                String jwtToken = jwtUtil.generateToken(loginRequest.getUsername(), userId, roles);
                
                // 记录新Token
                String tokenId = jwtUtil.getTokenIdFromToken(jwtToken);
                tokenBlacklistService.recordUserToken(userId, tokenId);
                
                response.put("success", true);
                response.put("message", "登录成功");
                response.put("redirectUrl", "/auth/user-console");
                response.put("userRole", userRole);
                response.put("token", jwtToken);
                
                log.info("用户登录成功: {}, 角色: {}", loginRequest.getUsername(), userRole);
            } else {
                response.put("success", false);
                response.put("message", "登录渠道、账户或密码不正确，请重试");
                log.warn("用户登录失败: {}", loginRequest.getUsername());
            }
            
        } catch (Exception e) {
            log.error("用户登录处理异常: {}", e.getMessage(), e);
            response.put("success", false);
            response.put("message", "系统异常，请稍后再试");
        }
        
        return response;
    }

    /**
     * 管理员登录处理
     */
    @PostMapping("/admin-login")
    @ResponseBody
    public Map<String, Object> adminLogin(@RequestBody LoginRequest loginRequest, HttpSession session) {
        Map<String, Object> response = new HashMap<>();
        
        try {
            log.info("管理员登录请求: {}", loginRequest.getUsername());
            
            // 验证管理员凭据
            if (isValidUser(loginRequest.getUsername(), loginRequest.getPassword())) {
                String userRole = getUserRole(loginRequest.getUsername(), "ADMIN");
                
                // 检查是否为管理员
                if (!"ADMIN".equals(userRole)) {
                    response.put("success", false);
                    response.put("message", "登录渠道、账户或密码不正确，请重试");
                    log.warn("非管理员用户尝试通过管理员渠道登录: {}, 角色: {}", loginRequest.getUsername(), userRole);
                    return response;
                }
                
                // 登录成功，设置session
                Long userId = getUserId(loginRequest.getUsername(), "ADMIN");
                session.setAttribute("username", loginRequest.getUsername());
                session.setAttribute("userId", userId);
                session.setAttribute("userRole", userRole);
                session.setAttribute("isAuthenticated", true);
                
                // 生成JWT Token供前端使用
                Set<String> roles = new HashSet<>();
                roles.add(userRole);
                
                // 撤销该用户的旧Token
                tokenBlacklistService.revokeUserTokens(userId);
                
                String jwtToken = jwtUtil.generateToken(loginRequest.getUsername(), userId, roles);
                
                // 记录新Token
                String tokenId = jwtUtil.getTokenIdFromToken(jwtToken);
                tokenBlacklistService.recordUserToken(userId, tokenId);
                
                response.put("success", true);
                response.put("message", "管理员登录成功");
                response.put("redirectUrl", "/auth/admin-console");
                response.put("userRole", userRole);
                response.put("token", jwtToken);
                
                log.info("管理员登录成功: {}, 角色: {}", loginRequest.getUsername(), userRole);
            } else {
                response.put("success", false);
                response.put("message", "登录渠道、账户或密码不正确，请重试");
                log.warn("管理员登录失败: {}", loginRequest.getUsername());
            }
            
        } catch (Exception e) {
            log.error("管理员登录处理异常: {}", e.getMessage(), e);
            response.put("success", false);
            response.put("message", "系统异常，请稍后再试");
        }
        
        return response;
    }

    /**
     * 用户注册处理
     */
    @PostMapping("/register")
    @ResponseBody
    public Map<String, Object> userRegister(@RequestBody RegisterRequest registerRequest) {
        Map<String, Object> response = new HashMap<>();
        
        try {
            log.info("用户注册请求: {}", registerRequest.getUsername());
            
            // 验证输入数据
            String validationError = validateRegisterData(registerRequest);
            if (validationError != null) {
                response.put("success", false);
                response.put("message", validationError);
                return response;
            }
            
            // 检查用户名是否已存在
            if (isUsernameExists(registerRequest.getUsername())) {
                response.put("success", false);
                response.put("message", "用户名已存在，请选择其他用户名");
                log.warn("注册失败，用户名已存在: {}", registerRequest.getUsername());
                return response;
            }
            
            // 检查邮箱是否已存在
            if (isEmailExists(registerRequest.getEmail())) {
                response.put("success", false);
                response.put("message", "邮箱地址已被使用，请使用其他邮箱");
                log.warn("注册失败，邮箱已存在: {}", registerRequest.getEmail());
                return response;
            }
            
            // 创建新用户
            boolean success = createNewUser(registerRequest);
            if (success) {
                response.put("success", true);
                response.put("message", "注册成功！请使用您的账号密码登录系统");
                log.info("用户注册成功: {}", registerRequest.getUsername());
            } else {
                response.put("success", false);
                response.put("message", "注册失败，请稍后再试");
                log.error("用户注册失败: {}", registerRequest.getUsername());
            }
            
        } catch (Exception e) {
            log.error("用户注册处理异常: {}", e.getMessage(), e);
            response.put("success", false);
            response.put("message", "系统异常，请稍后再试");
        }
        
        return response;
    }

    /**
     * 创建管理员账户（仅根管理员可操作）
     */
    @PostMapping("/create-admin")
    @ResponseBody
    public Map<String, Object> createAdminAccount(@RequestBody CreateAdminRequest createAdminRequest, HttpSession session) {
        Map<String, Object> response = new HashMap<>();
        
        try {
            // 验证当前用户是否为根管理员
            String currentUser = (String) session.getAttribute("username");
            String currentUserRole = (String) session.getAttribute("userRole");
            
            if (!"ROOT_ADMIN".equals(currentUserRole)) {
                response.put("success", false);
                response.put("message", "权限不足，只有根管理员可以创建管理员账户");
                log.warn("非根管理员用户尝试创建管理员账户: {}, 角色: {}", currentUser, currentUserRole);
                return response;
            }
            
            log.info("根管理员 {} 请求创建管理员账户: {}", currentUser, createAdminRequest.getUsername());
            
            // 验证输入数据
            String validationError = validateCreateAdminData(createAdminRequest);
            if (validationError != null) {
                response.put("success", false);
                response.put("message", validationError);
                return response;
            }
            
            // 检查用户名是否已存在
            if (isUsernameExists(createAdminRequest.getUsername())) {
                response.put("success", false);
                response.put("message", "用户名已存在，请选择其他用户名");
                log.warn("创建管理员失败，用户名已存在: {}", createAdminRequest.getUsername());
                return response;
            }
            
            // 检查邮箱是否已存在
            if (isEmailExists(createAdminRequest.getEmail())) {
                response.put("success", false);
                response.put("message", "邮箱地址已被使用，请使用其他邮箱");
                log.warn("创建管理员失败，邮箱已存在: {}", createAdminRequest.getEmail());
                return response;
            }
            
            // 创建管理员账户
            boolean success = createNewAdmin(createAdminRequest, currentUser);
            if (success) {
                response.put("success", true);
                response.put("message", "管理员账户创建成功！用户名: " + createAdminRequest.getUsername());
                log.info("根管理员 {} 成功创建管理员账户: {}", currentUser, createAdminRequest.getUsername());
            } else {
                response.put("success", false);
                response.put("message", "创建管理员账户失败，请稍后再试");
                log.error("创建管理员账户失败: {}", createAdminRequest.getUsername());
            }
            
        } catch (Exception e) {
            log.error("创建管理员账户处理异常: {}", e.getMessage(), e);
            response.put("success", false);
            response.put("message", "系统异常，请稍后再试");
        }
        
        return response;
    }

    /**
     * 用户注销
     */
    @PostMapping("/logout")
    @ResponseBody
    public Map<String, Object> logout(HttpSession session) {
        Map<String, Object> response = new HashMap<>();
        
        try {
            String username = (String) session.getAttribute("username");
            String userRole = (String) session.getAttribute("userRole");
            session.invalidate();
            
            // 根据用户角色决定跳转的登录页面
            String redirectUrl = "ADMIN".equals(userRole) ? "/auth/admin-login" : "/auth/user-login";
            
            response.put("success", true);
            response.put("message", "注销成功");
            response.put("redirectUrl", redirectUrl);
            
            log.info("用户注销成功: {}, 角色: {}", username, userRole);
            
        } catch (Exception e) {
            log.error("注销处理异常: {}", e.getMessage(), e);
            response.put("success", false);
            response.put("message", "注销失败");
        }
        
        return response;
    }

    /**
     * 检查登录状态
     */
    @GetMapping("/status")
    @ResponseBody
    public Map<String, Object> checkStatus(HttpSession session) {
        Map<String, Object> response = new HashMap<>();
        
        Boolean isAuthenticated = (Boolean) session.getAttribute("isAuthenticated");
        String username = (String) session.getAttribute("username");
        
        response.put("isAuthenticated", isAuthenticated != null && isAuthenticated);
        response.put("username", username);
        response.put("userRole", session.getAttribute("userRole"));
        
        return response;
    }

    /**
     * 控制台页面（需要登录）
     */
    @GetMapping("/console")
    public ModelAndView console(HttpSession session) {
        Boolean isAuthenticated = (Boolean) session.getAttribute("isAuthenticated");
        
        if (isAuthenticated == null || !isAuthenticated) {
            return new ModelAndView("redirect:/auth/user-login");
        }
        
        // 根据用户角色重定向到相应的控制台
        String userRole = (String) session.getAttribute("userRole");
        if ("ADMIN".equals(userRole)) {
            return new ModelAndView("redirect:/auth/admin-console");
        } else {
            return new ModelAndView("redirect:/auth/user-console");
        }
    }

    /**
     * 用户控制台页面
     */
    @GetMapping("/user-console")
    public ModelAndView userConsole(HttpSession session) {
        Boolean isAuthenticated = (Boolean) session.getAttribute("isAuthenticated");
        String userRole = (String) session.getAttribute("userRole");
        
        // 如果session中没有认证信息，直接返回dashboard页面，让前端通过JWT处理
        if (isAuthenticated == null || !isAuthenticated) {
            log.warn("Session认证信息缺失，返回dashboard页面由JWT处理认证");
            ModelAndView mv = new ModelAndView("user-dashboard");
            // 提供默认值，避免模板错误
            mv.addObject("username", "用户");
            mv.addObject("userId", 0L);
            mv.addObject("userRole", "USER");
            return mv;
        }
        
        ModelAndView mv = new ModelAndView("user-dashboard");
        mv.addObject("username", session.getAttribute("username"));
        mv.addObject("userId", session.getAttribute("userId"));
        mv.addObject("userRole", userRole);
        
        return mv;
    }

    /**
     * 管理员控制台页面
     */
    @GetMapping("/admin-console")
    public ModelAndView adminConsole(HttpSession session) {
        Boolean isAuthenticated = (Boolean) session.getAttribute("isAuthenticated");
        String userRole = (String) session.getAttribute("userRole");
        
        if (isAuthenticated == null || !isAuthenticated || !"ADMIN".equals(userRole)) {
            log.warn("非管理员用户尝试访问管理员控制台: {}", session.getAttribute("username"));
            return new ModelAndView("redirect:/auth/admin-login");
        }
        
        ModelAndView mv = new ModelAndView("admin-dashboard");
        mv.addObject("username", session.getAttribute("username"));
        mv.addObject("userId", session.getAttribute("userId"));
        mv.addObject("userRole", userRole);
        
        return mv;
    }

    /**
     * 验证用户凭据（数据库实现）
     */
    private boolean isValidUser(String username, String password) {
        try {
            // 首先尝试作为普通用户验证
            Optional<User> userOpt = userService.findByUsername(username);
            if (userOpt.isPresent()) {
                User user = userOpt.get();
                return user.getIsActive() && passwordEncoder.matches(password, user.getPassword());
            }
            
            // 如果不是普通用户，尝试作为管理员验证
            Optional<Admin> adminOpt = adminRepository.findByUsername(username);
            if (adminOpt.isPresent()) {
                Admin admin = adminOpt.get();
                return passwordEncoder.matches(password, admin.getPassword());
            }
            
            return false;
        } catch (Exception e) {
            log.error("验证用户凭据时发生异常: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 获取用户角色（数据库实现）
     * @param username 用户名
     * @param userType 用户类型 ("ADMIN" 或 "USER")
     */
    private String getUserRole(String username, String userType) {
        try {
            if ("ADMIN".equals(userType)) {
                // 管理员登录 - 只检查Admin表
                Optional<Admin> adminOpt = adminRepository.findByUsername(username);
                if (adminOpt.isPresent()) {
                    return "ADMIN";
                }
            } else {
                // 普通用户登录 - 只检查User表
                Optional<User> userOpt = userService.findByUsername(username);
                if (userOpt.isPresent()) {
                    User user = userOpt.get();
                    if (user.getRoles() != null && user.getRoles().contains(User.UserRole.ADMIN)) {
                        return "ADMIN";
                    }
                    return "USER";
                }
            }
            
            return "USER"; // 默认角色
        } catch (Exception e) {
            log.error("获取用户角色时发生异常: {}", e.getMessage(), e);
            return "USER";
        }
    }
    
    /**
     * 获取用户角色（向后兼容的重载方法）
     */
    private String getUserRole(String username) {
        return getUserRole(username, "USER"); // 默认作为普通用户处理
    }

    /**
     * 获取用户ID（数据库实现）
     * @param username 用户名
     * @param userType 用户类型 ("ADMIN" 或 "USER")
     */
    private Long getUserId(String username, String userType) {
        try {
            if ("ADMIN".equals(userType)) {
                // 管理员登录 - 只检查Admin表
                Optional<Admin> adminOpt = adminRepository.findByUsername(username);
                if (adminOpt.isPresent()) {
                    return adminOpt.get().getAdminId();
                }
            } else {
                // 普通用户登录 - 只检查User表
                Optional<User> userOpt = userService.findByUsername(username);
                if (userOpt.isPresent()) {
                    return userOpt.get().getUserId();
                }
            }
            
            return null;
        } catch (Exception e) {
            log.error("获取用户ID时发生异常: {}", e.getMessage(), e);
            return null;
        }
    }
    
    /**
     * 获取用户ID（向后兼容的重载方法）
     */
    private Long getUserId(String username) {
        return getUserId(username, "USER"); // 默认作为普通用户处理
    }

    /**
     * 验证注册数据
     */
    private String validateRegisterData(RegisterRequest request) {
        // 用户名验证
        if (request.getUsername() == null || request.getUsername().trim().isEmpty()) {
            return "用户名不能为空";
        }
        if (!Pattern.matches("^[a-zA-Z0-9]{3,20}$", request.getUsername())) {
            return "用户名必须3-20位，只能包含字母和数字";
        }
        
        // 密码验证
        if (request.getPassword() == null || request.getPassword().length() < 6) {
            return "密码长度不能少于6位";
        }
        
        // 邮箱验证
        if (request.getEmail() == null || request.getEmail().trim().isEmpty()) {
            return "邮箱地址不能为空";
        }
        if (!Pattern.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", request.getEmail())) {
            return "请输入正确的邮箱地址";
        }
        
        return null; // 验证通过
    }

    /**
     * 检查用户名是否已存在
     */
    private boolean isUsernameExists(String username) {
        try {
            // 检查普通用户表
            Optional<User> userOpt = userService.findByUsername(username);
            if (userOpt.isPresent()) {
                return true;
            }
            
            // 检查管理员表
            Optional<Admin> adminOpt = adminRepository.findByUsername(username);
            return adminOpt.isPresent();
        } catch (Exception e) {
            log.error("检查用户名存在性时发生异常: {}", e.getMessage(), e);
            return true; // 发生异常时返回true，避免重复用户名
        }
    }

    /**
     * 检查邮箱是否已存在
     */
    private boolean isEmailExists(String email) {
        try {
            if (email == null || email.trim().isEmpty()) {
                return false;
            }
            return userService.existsByEmail(email);
        } catch (Exception e) {
            log.error("检查邮箱存在性时发生异常: {}", e.getMessage(), e);
            return true; // 发生异常时返回true，避免重复邮箱
        }
    }

    /**
     * 创建新用户
     */
    private boolean createNewUser(RegisterRequest request) {
        try {
            log.info("创建新用户: username={}, email={}", 
                request.getUsername(), request.getEmail());
            
            // 使用UserService创建用户
            return userService.createUser(
                request.getUsername(),
                request.getPassword(),
                request.getEmail()
            );
        } catch (Exception e) {
            log.error("创建用户失败", e);
            return false;
        }
    }

    /**
     * 注册请求实体类
     */
    public static class RegisterRequest {
        private String username;
        private String password;
        private String email;

        // Getters and Setters
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
    }

    /**
     * 验证创建管理员数据
     */
    private String validateCreateAdminData(CreateAdminRequest request) {
        // 用户名验证
        if (request.getUsername() == null || request.getUsername().trim().isEmpty()) {
            return "用户名不能为空";
        }
        if (!Pattern.matches("^[a-zA-Z0-9]{3,20}$", request.getUsername())) {
            return "用户名必须3-20位，只能包含字母和数字";
        }
        
        // 密码验证
        if (request.getPassword() == null || request.getPassword().length() < 8) {
            return "管理员密码长度不能少于8位";
        }
        
        // 邮箱验证
        if (request.getEmail() == null || request.getEmail().trim().isEmpty()) {
            return "邮箱地址不能为空";
        }
        if (!Pattern.matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", request.getEmail())) {
            return "请输入正确的邮箱地址";
        }
        
        
        return null; // 验证通过
    }

    /**
     * 创建新管理员
     */
    private boolean createNewAdmin(CreateAdminRequest request, String createdBy) {
        try {
            // Mock实现，实际项目中应该保存到数据库
            log.info("创建新管理员: username={}, email={}, createdBy={}", 
                request.getUsername(), request.getEmail(), createdBy);
            
            // 这里可以添加实际的数据库操作：
            // 1. 密码加密存储
            // 2. 保存管理员信息到数据库，角色设为ADMIN
            // 3. 记录创建日志
            // 4. 发送账户创建通知邮件
            
            return true; // Mock成功
        } catch (Exception e) {
            log.error("创建管理员失败", e);
            return false;
        }
    }

    /**
     * 创建管理员请求实体类
     */
    public static class CreateAdminRequest {
        private String username;
        private String password;
        private String email;
        private String department;
        private String remarks;

        // Getters and Setters
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public String getEmail() { return email; }
        public void setEmail(String email) { this.email = email; }
        public String getDepartment() { return department; }
        public void setDepartment(String department) { this.department = department; }
        public String getRemarks() { return remarks; }
        public void setRemarks(String remarks) { this.remarks = remarks; }
    }
}